package com.easyaop.api.spring;

import com.easyaop.api.around.Around;
import com.easyaop.api.around.Call;
import com.easyaop.api.join.JoinPoint;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

@RequiredArgsConstructor
public class FromMethodInterceptor implements Around {
    private final MethodInterceptor methodInterceptor;

    @Override
    @SneakyThrows
    public Object around(Object target, Object[] args, JoinPoint joinPoint, Call call) throws Exception {

        Method method = joinPoint.getJavaMethod();

        return methodInterceptor.invoke(new ReflectiveMethodInvocation(null, target
                , method, args
                , method.getDeclaringClass(), new ArrayList<>()
        ) {
            @Override
            public Object proceed() throws Throwable {
                return call.call();
            }
        });
    }
}

class ReflectiveMethodInvocation extends org.springframework.aop.framework.ReflectiveMethodInvocation {
    /**
     * Construct a new ReflectiveMethodInvocation with the given arguments.
     *
     * @param proxy                                the proxy object that the invocation was made on
     * @param target                               the target object to invoke
     * @param method                               the method to invoke
     * @param arguments                            the arguments to invoke the method with
     * @param targetClass                          the target class, for MethodMatcher invocations
     * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied,
     *                                             along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime.
     *                                             MethodMatchers included in this struct must already have been found to have matched
     *                                             as far as was possibly statically. Passing an array might be about 10% faster,
     *                                             but would complicate the code. And it would work only for static pointcuts.
     */
    public ReflectiveMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
    }
}
